/*
 *  arith.c
 *
 *  Created on: 2010-5-12
 *      Author: liuyond
 *    Abstract: this file will implement the simulation of the following instruction
 *    			ADC, ADD, SBB, SUB, CMP, NEG, INC, DEC
 */
#include "cpu.h"
#include <stdio.h>

void ADD_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src + dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src + dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADD_BYTE, src, dst, ret);
}

void ADD_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src + dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src + dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADD_WORD, src, dst, ret);
}

void ADD_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src + dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src + dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, ADD_BYTE, src, dst, ret);
}

void ADD_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src + dst;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src + dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADD_WORD, src, dst, ret);
}

void ADD_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src + dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src + dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADD_BYTE, src, dst, ret);
}

void ADD_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src + dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src + dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADD_WORD, src, dst, ret);
}

void ADD_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src + dst;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, ADD_BYTE, src, dst, ret);
}

void ADD_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src + dst;
	cpu_set_regb(cpu, AX, ret);
	cpu_set_flags(cpu, ADD_WORD, src, dst, ret);
}

void ADC_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src + dst + cf;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src + dst + cf;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADC_BYTE, src, dst, ret);
}

void ADC_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src + dst + cf;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src + dst + cf;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADC_WORD, src, dst, ret);
}

void ADC_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src + dst + cf;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src + dst + cf;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, ADC_BYTE, src, dst, ret);
}

void ADC_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src + dst + cf;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src + dst + cf;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADC_WORD, src, dst, ret);
}

void ADC_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	src = i->operand.imm;
	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src + dst + cf;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src + dst + cf;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADC_BYTE, src, dst, ret);
}

void ADC_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	src = i->operand.imm;
	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src + dst + cf;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src + dst + cf;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, ADC_WORD, src, dst, ret);
}

void ADC_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf  = cpu_get_flag(cpu, CF);
	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src + dst + cf;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, ADC_BYTE, src, dst, ret);
}

void ADC_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf  = cpu_get_flag(cpu, CF);
	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src + dst + cf;
	cpu_set_regb(cpu, AX, ret);
	cpu_set_flags(cpu, ADC_WORD, src, dst, ret);
}

void SUB_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SUB_BYTE, src, dst, ret);
}

void SUB_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SUB_WORD, src, dst, ret);
}

void SUB_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, SUB_BYTE, src, dst, ret);
}

void SUB_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, SUB_WORD, src, dst, ret);
}

void SUB_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = dst - src;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, SUB_BYTE, src, dst, ret);
}

void SUB_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = dst - src;
	cpu_set_reg(cpu, AX, ret);
	cpu_set_flags(cpu, SUB_WORD, src, dst, ret);
}

void SUB_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SUB_BYTE, src, dst, ret);
}

void SUB_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SUB_WORD, src, dst, ret);
}

void SBB_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src - cf;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src - cf;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SBB_BYTE, src, dst, ret);
}

void SBB_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src - cf;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src - cf;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SBB_WORD, src, dst, ret);
}

void SBB_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src - cf;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src - cf;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, SBB_BYTE, src, dst, ret);
}

void SBB_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src - cf;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src - cf;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, SBB_WORD, src, dst, ret);
}

void SBB_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = dst - src - cf;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, SBB_BYTE, src, dst, ret);
}

void SBB_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	cf = cpu_get_flag(cpu, CF);
	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = dst - src - cf;
	cpu_set_reg(cpu, AX, ret);
	cpu_set_flags(cpu, SBB_WORD, src, dst, ret);
}

void SBB_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret, cf;

	src = i->operand.imm;
	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src - cf;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src - cf;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SBB_BYTE, src, dst, ret);
}

void SBB_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret, cf;

	src = i->operand.imm;
	cf = cpu_get_flag(cpu, CF);
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src - cf;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src - cf;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, SBB_WORD, src, dst, ret);
}

void CMP_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src;
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_BYTE, src, dst, ret);
}

void CMP_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src;
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_WORD, src, dst, ret);
}

void CMP_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src;
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_BYTE, src, dst, ret);
}

void CMP_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src;
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_WORD, src, dst, ret);
}

void CMP_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = dst - src;
	cpu_set_flags(cpu, SUB_BYTE, src, dst, ret);
}

void CMP_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = dst - src;
	cpu_set_flags(cpu, SUB_WORD, src, dst, ret);
}

void CMP_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src;
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_BYTE, src, dst, ret);
}

void CMP_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src;
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
	}
	cpu_set_flags(cpu, CMP_WORD, src, dst, ret);
}

void INC_RX(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;
	int  index = i->opcode & 0x7;

	dst = cpu_get_reg(cpu, index);
	src = 1; ret = dst + 1;
	cpu_set_reg(cpu, index, ret);
	cpu_set_flags(cpu, INC_WORD, src, dst, ret);
}

void INC_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src = 1, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst + src;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst + src;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, INC_BYTE, src, dst, ret);
}

void INC_Ev(cpu_t *cpu, instruction_t *i)
{
	word src = 1, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst + src;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst + src;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, INC_WORD, src, dst, ret);
}

void DEC_RX(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;
	int  index = i->opcode & 0x7;

	dst = cpu_get_reg(cpu, index);
	src = 1; ret = dst - 1;
	cpu_set_reg(cpu, index, ret);
	cpu_set_flags(cpu, DEC_WORD, src, dst, ret);
}

void DEC_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src = 1, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, DEC_BYTE, src, dst, ret);
}

void DEC_Ev(cpu_t *cpu, instruction_t *i)
{
	word src = 1, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = dst - src;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = dst - src;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, DEC_WORD, src, dst, ret);
}

void MUL_AL_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst;
	word ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, AL);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, AL);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret);
	}
	cpu_set_flags(cpu, MUL_BYTE, src, dst, ret);
}

void MUL_AX_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst;
	dword ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, AX);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret & 0xFFFF);
		cpu_set_reg(cpu, DX, (ret >> 16));
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, AX);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret & 0xFFFF);
		cpu_set_reg(cpu, DX, (ret >> 16));
	}
	cpu_set_flags(cpu, MUL_WORD, src, dst, ret);
}

void IMUL_AL_Eb(cpu_t *cpu, instruction_t *i)
{
	char src, dst;
	short ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, AL);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, AL);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret);
	}
	cpu_set_flags(cpu, MUL_BYTE, src, dst, ret);
}

void IMUL_AX_Ev(cpu_t *cpu, instruction_t *i)
{
	short src, dst;
	long ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, AX);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret & 0xFFFF);
		cpu_set_reg(cpu, DX, (ret >> 16));
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, AX);
		ret = dst * src;
		cpu_set_reg(cpu, AX, ret & 0xFFFF);
		cpu_set_reg(cpu, DX, (ret >> 16));
	}
	cpu_set_flags(cpu, MUL_WORD, src, dst, ret);
}

void DIV_AL_Eb(cpu_t *cpu, instruction_t *i)
{
	word tmp;
	byte src;
	byte ret;

	tmp = cpu_get_reg(cpu, AX);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
	}
	ret = tmp / src; cpu_set_regb(cpu, AL, ret);
	ret = tmp % src; cpu_set_regb(cpu, AH, ret);

}

void DIV_AX_Ev(cpu_t *cpu, instruction_t *i)
{
	dword tmp;
	word  src;
	word  ret;

	tmp = cpu_get_reg(cpu, DX);
	tmp = tmp << 16;
	tmp |= cpu_get_reg(cpu, AX);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
	}
	ret = tmp / src; cpu_set_reg(cpu, AX, ret);
	ret = tmp % src; cpu_set_reg(cpu, DX, ret);
}

void IDIV_AL_Eb(cpu_t *cpu, instruction_t *i)
{
	short tmp;
	char  src;
	char  ret;

	tmp = cpu_get_reg(cpu, AX);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
	}
	ret = tmp / src; cpu_set_regb(cpu, AL, ret);
	ret = tmp % src; cpu_set_regb(cpu, AH, ret);
}

void IDIV_AX_Ev(cpu_t *cpu, instruction_t *i)
{
	long  tmp;
	short src;
	short ret;

	tmp = cpu_get_reg(cpu, DX);
	tmp = tmp << 16;
	tmp |= cpu_get_reg(cpu, AX);
	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
	}
	ret = tmp / src; cpu_set_reg(cpu, AX, ret);
	ret = tmp % src; cpu_set_reg(cpu, DX, ret);
}

void DAA(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "DAA not implemented!\n");
}

void DAS(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "DAS not implemented!\n");
}

void AAA(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "AAA not implemented!\n");
}

void AAS(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "AAS not implemented!\n");
}

void AAM_Ib(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "AAM not implemented!\n");
}

void AAD_Ib(cpu_t *cpu, instruction_t *i)
{
	fprintf(stdout, "AAD not implemented!\n");
}
